//package com.pengzy.core.gateway_security;
//
//import cn.hutool.core.convert.Convert;
//import cn.hutool.core.util.ArrayUtil;
//import com.alibaba.fastjson2.JSONObject;
//import com.pengzy.core.conf.IgnoreUrlsConfig;
//import com.pengzy.core.servletWrapper.HttpServletRequestReplacedFilter;
//import lombok.extern.slf4j.Slf4j;
//import org.mybatis.spring.annotation.MapperScan;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.context.annotation.Bean;
//import org.springframework.core.io.buffer.DataBuffer;
//import org.springframework.http.HttpMethod;
//import org.springframework.http.server.reactive.ServerHttpRequest;
//import org.springframework.http.server.reactive.ServerHttpResponse;
//import org.springframework.security.authentication.*;
//import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
//import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
//import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
//import org.springframework.security.config.web.server.ServerHttpSecurity;
//import org.springframework.security.web.server.SecurityWebFilterChain;
//import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
//import org.springframework.web.server.ServerWebExchange;
//import reactor.core.publisher.Mono;
//
//import javax.annotation.Resource;
//import java.io.UnsupportedEncodingException;
//import java.util.List;
//import java.util.Map;
//
///**
// * @author xiaozhi 2023/7/17
// */
//
//@Slf4j
//@EnableWebFluxSecurity
//@EnableReactiveMethodSecurity
//@MapperScan(basePackages = {"com.pengzy.**.mapper","com.pengzy.**.**.mapper"})
//public class WebFluxSecurityConfigurer {
//
//
//
//    @Resource
//    private AuthenticationSuccessConfig authenticationSuccessConfig;
//    @Resource
//    private AuthenticationFailureConfig authenticationFailureConfig;
//    @Resource
//    private LogoutsSuccessConfig logoutsSuccessConfig;
//    @Resource
//    private AccessDeniedConfig accessDeniedConfig;
//    @Resource
//    private AuthenticationEntryPointConfig authenticationEntryPointConfig;
//
//    @Autowired
//    private IgnoreUrlsConfig ignoreUrlsConfig;
//
//    @Autowired
//    JwtSecurityContextRepository jwtSecurityContextRepository;
//
//
//    /**
//     * 提供用于获取UserDetails的Service
//     * @param userService
//     * @return
//     */
//    @Bean
//    public ReactiveAuthenticationManager authenticationManager(UserService userService) {
//        log.info("加载security 用户配置....");
//        return new UserDetailsRepositoryReactiveAuthenticationManager(userService);
//    }
//
//
//    /**
//     * http请求路径权限与过滤链配置
//     * @param http
//     * @param userService
//     * @return
//     */
//    @SuppressWarnings(value = {"all"})
//    @Bean
//    public SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http, UserService userService) throws Exception {
//
//        log.info("加载security 权限配置....");
//        ServerHttpSecurity.AuthorizeExchangeSpec authorizeExchangeSpec = http
//                .csrf().disable()
//                .cors().configurationSource(new CrosConfig().crosBase()).and() //允许跨域访问
//                .httpBasic().disable()
//                .securityContextRepository(jwtSecurityContextRepository) //认证方式，这是自己的实现类，实现load方法
//                //.addFilterAfter(loginFilter, SecurityWebFiltersOrder.LAST)
//               // .addFilterAfter(reactiveRequestContextFilter, SecurityWebFiltersOrder.HTTP_BASIC)
////                .formLogin()
////                .loginPage("/core/login")
////                .authenticationSuccessHandler(authenticationSuccessConfig) ////登录处理器(可以单独创建类处理)
////                .authenticationFailureHandler(authenticationFailureConfig) //验证失败处理器(可以单独创建类处理)仅仅调用登录接口验证失败后才走此代码
////                .and()
//                .logout().logoutUrl("/web/logout")
//                //只能是post方法才会走此
//                .logoutSuccessHandler(logoutsSuccessConfig) ////退出成功处理器(可以单独创建类处理)
//                .and().exceptionHandling() //异常处理
//                .accessDeniedHandler(accessDeniedConfig) // 无权限访问处理器(可以单独创建类处理)
//                .authenticationEntryPoint(authenticationEntryPointConfig) ////认证失败处理
//                .and().authorizeExchange();
//
//        //判断某个url可以多个角色访问 .pathMatchers(“路径”).access(“可访问角色列表”)
////        deniedMap.forEach((path,roles)->{
////            authorizeExchangeSpec.pathMatchers(path)
////                    .access((authentication, object) -> {
////                        return authentication.map(authentications -> {
////                            boolean anyMatch = authentications.getAuthorities().stream().anyMatch(s1 -> {
////                                return s1.getAuthority().replace("ROLE_","").matches("^"+roles+"$"); //这是正则匹配，填写 2|3例子
////                            });
////                            return new AuthorizationDecision(anyMatch);
////                        });
////                    });
////        });
//        authorizeExchangeSpec//请求进行授权
//                .pathMatchers(HttpMethod.OPTIONS).permitAll()//特殊请求过滤
//                .pathMatchers("/cloud-config-server/**").denyAll() //禁止通过gateway访问配置中心
//                .pathMatchers(Convert.toStrArray(ArrayUtil.toArray(ignoreUrlsConfig.getUrls(),String.class))).permitAll()//登录不需要验证
////                .pathMatchers("/index").hasRole("3") //路径授权和代码先后也有顺序。意思就是说如果上面的代码匹配成功了，就不会继续往下走
//                .matchers((serverWebExchange)->{ //自定义验证授权规则，如果此方法成立，那么配合permitAll()方法进行放行逻辑
//                    try {
//                        ServerHttpRequest serverHttpRequest = serverWebExchange.getRequest();//获取请求对象
//                        //发现经过nginx转发之后，获取到的ip不再是访问者的ip，竟然是nginx服务器所在的ip，就是node101.这是个问题   nginx配置： proxy_pass http://192.168.0.103:28088
//                        //上述问题已解决：配置External Traffic Policy:  Local即可
//                        String remoteHostAddress = serverHttpRequest.getRemoteAddress().getAddress().getHostAddress();//获取调用方的IP地址，如果符合条件则放行,如果某个路径配置了access权限，那么此路径不会走此处了
//                        //proxy_set_header   Remote_Addr    $remote_addr;可以获取真实的IP，但是我部署在k8s中，又多了几层代理，所以还是没有获取到IP，需配置下才行。或者把nginx服务部署到物理机
//                        List<String> whoFlag = serverHttpRequest.getHeaders().get("whoFlag"); //如果是走的nginx转发，那么一定有此值，因为我配置了， proxy_set_header   whoFlag  ssx-k8s-docker-nginx;
//                        List<String> remoteAddr = serverHttpRequest.getHeaders().get("Remote_Addr"); //当走nginx转发时，获取此值 真实用户IP
//                        //配置k8s的service： nginx和ssx-web-base两个服务配置yaml => External Traffic Policy:  Local
//                        //情况1，调用方直接调用gateway服务，这种情况只可能是我内网的调用，给予放行。 此时用户IP取 remoteHostAddress
//                        //情况2，调用方经过nginx转发到gateway，这种情况都是外网访问。因为外网想要访问只能走nginx。 此时用户IP取 remoteAddr
//                        if (whoFlag != null) {
//                            if (remoteAddr!=null){
//                                throw new RuntimeException("访问者IP："+remoteAddr.get(0)+" 走的是nginx代理，是外网访问资源，这里不允许免认证！path:"+serverHttpRequest.getPath());
//                            }
//                            throw new RuntimeException("访问者IP："+remoteHostAddress+" 走的是nginx代理，是外网访问资源，这里不允许免认证！path:"+serverHttpRequest.getPath());
//                        }
//                        if (remoteHostAddress.matches("^192\\.168\\.0\\.\\d{1,3}$")) {
//                            log.warn("gateway权鉴security配置远程ip地址免认证放行,ip:{},path:{}",remoteHostAddress,serverHttpRequest.getPath());
//                            return ServerWebExchangeMatcher.MatchResult.match();
//                        }
//                        return ServerWebExchangeMatcher.MatchResult.notMatch();
//                    }catch (Exception e){
//                        log.warn(e.getMessage());
//                        return ServerWebExchangeMatcher.MatchResult.notMatch();
//                    }
//                }).permitAll()
//                .anyExchange()//任何请求
//                .authenticated();//都需要身份认证;
//
//        SecurityWebFilterChain chain = http.build();
//        return chain;
//    }
//
//    /**
//     * 输出响应信息
//     * @param exchange
//     * @param responseMap
//     * @return
//     */
//    public Mono<Void> writeWith(ServerWebExchange exchange, Map<String, String> responseMap){
//        ServerHttpResponse response = exchange.getResponse();
//        String body = JSONObject.toJSONString(responseMap);
//        DataBuffer buffer = null;
//        try{
//            buffer = response.bufferFactory().wrap(body.getBytes("UTF-8"));
//        }catch(UnsupportedEncodingException ue){
//            ue.printStackTrace();
//        }
//        return response.writeWith(Mono.just(buffer));
//    }
//
//
//
//
//}
